/*
 *  Copyright 2012 yura.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package org.opu.nlp.pos.rnc_corpus;

import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.opu.nlp.pos.rnc_corpus.beans.Composit;
import org.opu.nlp.pos.rnc_corpus.beans.Corpus;
import org.opu.nlp.pos.rnc_corpus.beans.HasAttributes;
import org.opu.nlp.pos.rnc_corpus.beans.HasText;
import org.opu.nlp.pos.rnc_corpus.beans.Verifiable;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author yura
 */
public class SaxCorpusXmlParser implements CorpusXmlParser {

    private static final SAXParserFactory factory = SAXParserFactory.newInstance();

    private ObjectFactory objectFactory;

    private Stack objects = new Stack();
    private Object last;

    public SaxCorpusXmlParser(ObjectFactory objectFactory) {
        this.objectFactory = objectFactory;
    }

    @Override
    public Corpus parseXml(InputStream stream) throws IOException {
        try {
            return parseXmlImpl(stream);
        } catch (SAXException ex) {
            throw new IOException(ex);
        } catch (ParserConfigurationException ex) {
            throw new IOException(ex);
        } finally {
            objects.clear();
            last = null;
        }
    }

    public Corpus parseXmlImpl(InputStream stream) throws IOException,
            SAXException, ParserConfigurationException {

        SAXParser sp = null;
        sp = factory.newSAXParser();

        sp.parse(stream, new DefaultHandler(){

            @Override
            public void startElement(String uri, String localName, String qName,
                    Attributes attributes) throws SAXException {
                if (objects.push(objectFactory.getObjectByTagName(localName))
                        instanceof HasAttributes) {
                    HasAttributes ha = (HasAttributes) objects.peek();

                    for (int i = 0; i < attributes.getLength(); i++) {
                        ha.setAttribute(attributes.getLocalName(i),
                                attributes.getValue(i));
                    }
                }
            }

            @Override
            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                last = objects.pop();
                if (last instanceof Verifiable) {
                    ((Verifiable)last).verify();
                }
                if (!objects.isEmpty() && objects.peek() instanceof Composit) {
                    ((Composit)objects.peek()).addComposit(last);
                }
            }

            @Override
            public void characters(char[] ch, int start, int length)
                    throws SAXException {
                if (objects.peek() instanceof HasText) {
                    ((HasText)objects.peek()).setText(new String(ch, start, length));
                }
            }

        });
        
        return (Corpus) last;
    }

}
